/*workfloe 执行
  begin 2025/1/12
*/
(function ($) {
    $.fn.yqFlowView = function (opts, param) {
        if (typeof opts == 'string') {
            return $.fn.yqFlowView.methods[opts](this, param);
        }

        var $this = this;
        var opt;
        if ($this.data("yqtype") == "yqFlowView") {
            destroy($this);
        }

        opt = $.extend({}, $.fn.yqFlowView.defaults, opts);
        var $uniqueID = $this.attr("ID");
        if ($uniqueID === undefined || $uniqueID === null || $uniqueID == "") {
            $uniqueID = $.getUniqueID();
            $this.attr("ID", $uniqueID);
        }

        if (opt.width === undefined) {
            if ($this.width() > 0) {
                opt.width = $this.width();
            } else {
                opt.width = 450;
            }
        }
        else {
            $this.width(opt.width);
        }

        if (opt.height === undefined) {
            if ($this.height() > 0) {
                opt.height = $this.height();
            } else {
                opt.height = 400;
            }
        }
        else {
            $this.height(opt.height);
        }

        opt._flowstate = {};

        if (!(opt.type == 0 || opt.type == 1 || opt.type == 2)) {
            opt.type = 0;
        }

        //变量信息
        $this.data("flowview_opt", opt);
        $this.data("yqtype", "yqFlowView");

        if (opt.isFlow) {
            LoadJsCss(function () {
                opt.beforeBindingTitle.call($this, function () {
                    init_html($this);
                });
            });
        } else {
            init_html_2($this);
        }
    };

    $.fn.yqFlowView.defaults = {
        ajaxUrl: "/_db.html",
        isFlow: true,    //是流程图显示
        initId: null,   //实例流程id
        value: {},
        type: 0,  //0-本地测试,1-服务端测试,2-执行流程
        users: [], //当前审批人 除了本人，还可以代理其他人审批
        admin: false, //管理员
        beforeBindingTitle: function (callback) {
            callback();
        }, //标题绑定前
        afterBindingTitle: function () { },   //标题绑定后
        beforeSubmit: function (res, callback) {  //审批提交前
            callback(true, res);
        },
        afterSubmit: function (res) {     //审批提交后
        }
    };

    $.fn.yqFlowView.methods = {
        options: function (jq) {
            return options(jq);
        },
        resize: function (jq, res) {
            var opt = options(jq);
            resize(jq, res);
        },
        destroy: function (jq) {
            var $object = jq;
            destroy($object);
        },
        setValue: function (jq, val) {
            load(jq, val);
        },
        clear: function (jq) {
            load(jq, {});
        },
        getValue: function (jq) {
            return getModel(jq);
        },
        setType: function (jq, type) {
            options(jq).type = type;
        },
        save: function (jq, filename) {
            saveDiagram(jq, filename);
        },
        load: function (jq) {
            loadFile(jq);
        },
        menuEnable: function (jq) {  //打印
            printDiagram(jq);
        },
    }

    function LoadJsCss(callback) {
        var file = [];
        file.push({ url: "/scripts/gojs/go.js", type: "js" });
        $.yqLoadJsCss(file, function () {
            callback();
        });
    }

    function options($object) {
        return $object.data("flowview_opt");
    }

    function destroy($object) {
        var opt = options($object);

        $object.empty();
    }

    function resize($object, res) {
        var opt = options($object);
        var $uniqueID = $object.attr("ID");

        if (res === undefined) {
            res = {};
        }

        if (!(res.width === undefined)) {
            opt.width = res.width;
        }
        if (!(res.height === undefined)) {
            opt.height = res.height;
        }

        $object.css({
            "width": (opt.width) + "px",
            "height": (opt.height) + "px"
        });

        var $diagram = $("#" + $uniqueID + "_diagram");
        $diagram.css({ "height": opt.height + "px" });
        $diagram.find("canvas").height(opt.height);
        $diagram.find("div").css({ "height": opt.height + "px" });
    }

    function form_load($object) {
        var opt = options($object);

        if (opt.isFlow) {
            resize($object);

            load($object);
        } else {
            load_2($object);
        }

        opt.afterBindingTitle.call($object);
    }

    //--- 流程图显示模式 begin ------------------------
    function init_html($object) {
        var opt = options($object);
        var $uniqueID = $object.attr("ID");

        $object.empty();

        var html_ = `
                <div id="_uniqueID_diagram"
                  style="flex-grow: 1; height: 810px; position: relative; background-color: rgb(20, 30, 55); cursor: auto; font: bold 11pt Figtree, sans-serif;">
                </div>
          `;

        html_ = html_.replace(/_uniqueID/g, $uniqueID);
        //console.log(html_);
        $object.append(html_);

        init_flow($object);
    }

    function init_flow($object) {
        var opt = options($object);
        var $uniqueID = $object.attr("ID");

        opt.$ = go.GraphObject.make;

        opt.diagram = new go.Diagram(
            $uniqueID + '_diagram',
            {
                'undoManager.isEnabled': true,
                'themeManager.changesDivBackground': true,
                'themeManager.currentTheme': opt.default_theme,
                "grid": opt.$(go.Panel,
                    'Grid',
                    opt.$(go.Shape, 'LineH', {
                        stroke: 'lightgray',
                        strokeWidth: 0.5
                    }),
                    opt.$(go.Shape, 'LineV', {
                        stroke: 'lightgray',
                        strokeWidth: 0.5
                    })
                ),
                isReadOnly: true,
                contextMenu: node_menu(),
            }
        );

        opt.diagram.grid.visible = false;
        opt.diagram.isReadOnly = true;

        opt.diagram.themeManager.set('light', {
            colors: {
                text: '#fff',
                //节点颜色
                start: '#064e3b',
                return: '#669933',
                exec: '#49939e',
                proc: '#0066CC',
                judge: '#6a9a8a',
                end: '#7f1d1d',
                cancle: '#FF9900',
                //待办节点
                start_boder_1: '#a9a9a9',
                return_boder_1: '#a9a9a9',
                exec_boder_1: '#a9a9a9',
                proc_boder_1: '#a9a9a9',
                judge_boder_1: '#a9a9a9',
                end_boder_1: '#a9a9a9',
                cancle_boder_1: '#a9a9a9',
                //完成节点
                start_boder_9: '#666666',
                return_boder_9: '#666666',
                exec_boder_9: '#666666',
                proc_boder_9: '#666666',
                judge_boder_9: '#666666',
                end_boder_9: '#666666',
                cancle_boder_9: '#666666',

                comment: '#a691cc',
                bgText: '#000',
                link: '#dcb263',
                linked: "#669933",   //线 state=9 执行
                linkOver: '#cbd5e1',
                div: '#ffffff',
            },
        });

        opt.diagram.themeManager.set('dark', {
            colors: {
                text: '#fff',
                start: '#064e3b',
                return: '#669933',
                exec: '#414a8d',
                proc: '#0066CC',
                judge: '#88afa2',
                cancle: '#FF9900',
                comment: '#bfb674',
                bgText: '#fff',
                link: '#fdb71c',
                linked: "#669933",   //线 state=9 执行
                linkOver: '#475569',
                div: '#141e37',
            },
        });

        defineFigures();

        //节点类型
        function nodeStyle_flow(node, s_type) {
            node
                .set({
                    locationSpot: go.Spot.Center,
                    locationObjectName: 'SHAPE',
                    desiredSize: new go.Size(75, 40),
                    minSize: new go.Size(40, 40),
                    resizable: true,
                    resizeCellSize: new go.Size(20, 20),

                    contextMenu: node_menu(),
                })
                .bindTwoWay('desiredSize', 'size', go.Size.parse, go.Size.stringify)
                .bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify);
        }

        //节点选择
        function selectionChanged_flow(node, s_type) {
            if (!(node.data.model === undefined)) {
                return;
            }

            if (s_type === undefined) {
                s_type = 9001;
            }

            if (node.isSelected) {
                var nodeData = node.data;
            } else {

            }
        }

        function shapeStyle(shape) {
            shape.set({
                portId: '',
                cursor: 'default',
                margin: 0,
                stroke: "red",     // 边框颜色
                strokeWidth: 0,    // 边框宽度

                toolTip: node_tooltip()
            }).bind("stroke", function (d) {

                var stroke = "red";
                if (d.todo == 1 || d.todo == 9) {
                    stroke = opt.diagram.themeManager.findValue(d.category.toLowerCase() + "_boder_" + d.todo, 'colors', this.currentTheme);
                }
                return stroke;
            }).bind("strokeWidth", function (d) {
                var width = 0;
                if (d.todo == 1) {        //待办
                    width = 3;
                } else if (d.todo == 9) { //完成
                    width = 3;
                }
                return width;
            });
        }

        function textStyle(textblock) {
            textblock
                .set({
                    font: 'bold 11pt Figtree, sans-serif',
                    cursor: "default",

                    toolTip: node_tooltip()
                })
                .theme('stroke', 'text');
        }
        //节点属性提示
        function node_tooltip() {
            return go.GraphObject.build("ToolTip").add(
                new go.Panel("Vertical").add(
                    new go.TextBlock({ margin: 3 })
                        .bind("text", function (data) {
                            return data.text + "\n"
                                + "执行人：aaa";
                        })
                )
            );
        }

        function node_source(data) {
            var source = "data:image/png;base64,"
            if (data.todo == 1) {   //待办
                //测试状态 或 当前审批人
                if ((opt.type == 0 || opt.type == 1 || opt.admin) || $_yqFlow.checkPower(data, opt.users)) {
                    source = "";
                } else {
                    source = "";
                }
            } else if (data.todo == 9) { //完成
                source = "";
            }
            return source;
        }

        function node_desiredSize(data) {
            var s_size = new go.Size(30, 30)
            if (data.todo == 1) {   //待办
                s_size = new go.Size(18, 18)
            } else if (data.todo == 9) { //完成
                s_size = new go.Size(20, 20)
            }
            return s_size;
        }

        /*
        主信息：
            9000 主信息
        节点
            9001 Start 开始节点
            9002 Return 退回节点

            9005 Exec 执行节点
            9007 Proc 程序节点
            9006 Judge 判断节点

            9008 Cancle 取消节点
            9009 End 结束节点

            9010 Comment 文档节点
        线
            9099 线
        */
        function node_menu() {
            var menus = go.GraphObject.build("ContextMenu");

            //提交流程
            menus.add(
                go.GraphObject.build("ContextMenuButton", {
                    click: function (e, obj) {
                        //var node = obj.part;
                        //console.log("发起流程", node.data);
                        var node = obj.part.data;
                        submit($object, e, node);
                    }
                }).add(new go.TextBlock({
                    text: "发起流程",
                    font: '10pt Figtree, sans-serif',
                    margin: new go.Margin(3, 12),
                    wrap: go.Wrap.Fit,
                }))
                    .bind("visible", function (data) {
                        //console.log("data", data);
                        var visible = false;

                        var wf_state = getModel($object).info.wfstate;
                        if (!(wf_state == 8 || wf_state == 9)) {
                            if (data.category == "Start" ||   //开始节点
                                data.category == "Return" ||  //退回节点
                                data.category == "Exec") {    //执行节点 
                                if (data.todo == 1 &&
                                    (opt.type == 0 || opt.type == 1 || opt.admin || $_yqFlow.checkPower(data, opt.users))
                                ) {
                                    visible = true;
                                }
                            }
                        }

                        return visible;
                    })
            );

            //查看详情
            menus.add(
                go.GraphObject.build("ContextMenuButton", {
                    click: function (e, obj) {
                        // var node = obj.part;
                        // console.log("查看详情", e, node.data);
                        // 获取点击位置的坐标
                        var point = e.viewPoint;
                        var prevent_e = {
                            $object: e,
                            clientX: point.x,
                            clientY: point.y,
                        };

                        var _pops = {
                            prevent_e: prevent_e,
                            mdiinfo: $.yqGetWindParams(),
                            width: 400,
                            height: 420,
                            horizontalAlign: "none",
                            verticalAlign: "none",
                            types: ["json"],
                            type: "json",
                            isEdit: false,
                            goDocEnd: false,
                        };

                        if (obj.part.data.text === undefined) {
                            var prevent_e = $.getPreventDefault($object);
                            prevent_e.clientY -= ($object.height() - 50);
                            prevent_e.clientX += 50;
                            _pops.prevent_e = {
                                $object: e,
                                clientX: prevent_e.clientX,
                                clientY: prevent_e.clientY,
                            }
                            _pops.width = $object.width() - 100;
                            _pops.height = $object.height() - 100;
                            if (_pops.width < 300) {
                                _pops.width = 300;
                            }
                            _pops.height = $object.height() - 100;
                            if (_pops.height < 300) {
                                _pops.height = 300;
                            }

                            _pops.value = JSON.stringify(getModel($object), null, 2);
                        } else {
                            var point = e.viewPoint;
                            _pops.prevent_e = {
                                $object: e,
                                clientX: point.x,
                                clientY: point.y,
                            };

                            _pops.value = JSON.stringify(obj.part.data, null, 2);
                        }

                        if (window.top == window.self) {
                            $.yqCodePopEdit(_pops);
                        }
                        else {
                            window.top.$.yqCodePopEdit(_pops);
                        }
                    }
                }).add(new go.TextBlock({
                    text: "查看详情",
                    font: '10pt Figtree, sans-serif',
                    margin: new go.Margin(3, 12),
                    wrap: go.Wrap.Fit,
                }))
            );

            return menus;
        }

        opt.diagram.nodeTemplateMap.add(
            'Exec',
            new go.Node('Auto').apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9005);
                    }
                }).add(
                    new go.Shape('Rectangle', {
                        fromLinkable: true,
                        toLinkable: true,
                        fromSpot: go.Spot.AllSides,
                        toSpot: go.Spot.AllSides,

                    })
                        .apply(shapeStyle)
                        .theme('fill', 'exec'),

                    new go.Picture({
                        source: "",
                        margin: 0,
                        desiredSize: new go.Size(24, 24),
                        alignment: go.Spot.TopRight,
                    }),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock({
                        margin: 12,
                        wrap: go.Wrap.Fit,
                    })
                        .apply(textStyle)
                        .bindTwoWay('text')
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'Proc',
            new go.Node('Auto').apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9007);
                    }
                }).add(
                    new go.Shape('Rectangle', {
                        fromLinkable: true,
                        toLinkable: true,
                        fromSpot: go.Spot.AllSides,
                        toSpot: go.Spot.AllSides,
                    })
                        .apply(shapeStyle)
                        .theme('fill', 'proc'),

                    new go.Picture({
                        source: "",
                        margin: 0,
                        desiredSize: new go.Size(24, 24),
                        alignment: go.Spot.TopRight,
                    }),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock({
                        margin: 12,
                        //maxSize: new go.Size(160, NaN),
                        wrap: go.Wrap.Fit,
                        //editable: true,
                    })
                        .apply(textStyle)
                        .bindTwoWay('text')
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'Judge',
            new go.Node('Auto').apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9006);
                    }
                }).add(
                    new go.Shape('Judge', {
                        fromLinkable: true,
                        toLinkable: true
                    }).apply(shapeStyle).theme('fill', 'judge'),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock({
                        margin: 8,
                        //maxSize: new go.Size(160, NaN),
                        wrap: go.Wrap.Fit,
                        textAlign: 'center',
                        //editable: true,
                    })
                        .apply(textStyle)
                        .bindTwoWay('text')
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'Start',
            new go.Node('Auto')
                .apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9001);
                    }
                })
                .add(
                    new go.Shape('Capsule', {
                        fromLinkable: true
                    }).apply(shapeStyle).theme('fill', 'start'),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock('Start', {
                        margin: new go.Margin(5, 6)
                    }).apply(textStyle).bind('text')
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'Return',
            new go.Node('Auto')
                .apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9002);
                    }
                })
                .add(
                    new go.Shape('Capsule', {
                        fromLinkable: true,
                        toLinkable: true
                    }).apply(shapeStyle).theme('fill', 'return'),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock('Return', {
                        margin: new go.Margin(5, 6)
                    }).apply(textStyle).bind('text')
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'End',
            new go.Node('Auto')
                .apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9009);
                    }
                })
                .add(
                    new go.Shape('Capsule', {
                        toLinkable: true
                    }).apply(shapeStyle).theme('fill', 'end'),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock('End', {
                        margin: new go.Margin(5, 6)
                    }).apply(textStyle).bind('text')
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'Cancle',
            new go.Node('Auto')
                .apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9008);
                    }
                })
                .add(
                    new go.Shape('Capsule', {
                        toLinkable: true,
                    }).apply(shapeStyle).theme('fill', 'cancle'),

                    new go.Picture({
                        margin: 0,
                        alignment: go.Spot.BottomRight,
                    })
                        .bind('source', node_source)
                        .bind('desiredSize', node_desiredSize),

                    new go.TextBlock('Cancle', {
                        margin: new go.Margin(5, 6)
                    }).apply(textStyle).bind('text'),
                )
        );

        opt.diagram.nodeTemplateMap.add(
            'Comment',
            new go.Node('Auto').apply(nodeStyle_flow)
                .set({
                    selectionChanged: function (node) {
                        selectionChanged_flow(node, 9010);
                    }
                })
                .add(
                    new go.Shape('File', {
                        strokeWidth: 3,
                        stretch: go.GraphObject.Fill // 确保 Shape 的宽度跟随 Node 的宽度
                    })
                        .theme('fill', 'div').theme('stroke', 'comment'),

                    // 使用 Panel 将两个 TextBlock 垂直排列
                    new go.Panel('Vertical', {
                        margin: new go.Margin(2, 5, 5, 5),
                        stretch: go.GraphObject.Fill
                    }).add(
                        new go.TextBlock({     // 显示 text
                            font: 'bold 11pt Figtree, sans-serif',
                            lineSpacing: 6,
                            margin: new go.Margin(0, 0, 8, 0),
                            wrap: go.Wrap.Fit,
                            isMultiline: false,   // 设置为单行文本
                            textAlign: 'center'
                        })
                            .bindTwoWay('text'),
                        new go.TextBlock({   // 显示 desc
                            font: '9pt Figtree, sans-serif',
                            lineSpacing: 16, // 设置行间距为 6
                            margin: new go.Margin(2, 0),
                            wrap: go.Wrap.Fit,
                            isMultiline: true,
                            textAlign: 'start'
                        })
                            .bindTwoWay('text', 'desc')
                    )
                )
        );

        opt.diagram.linkTemplate = new go.Link({
            routing: go.Routing.AvoidsNodes,
            curve: go.Curve.JumpOver,
            corner: 5,
            toShortLength: 4,
            relinkableFrom: true,
            relinkableTo: true,
            reshapable: true,
            resegmentable: true,
            mouseEnter: (e, link) => (link.findObject('HIGHLIGHT').stroke = link.diagram.themeManager.findValue('linkOver', 'colors')),
            mouseLeave: (e, link) => (link.findObject('HIGHLIGHT').stroke = 'transparent'),
            contextClick: (e, link) => {
                e.diagram.model.commit((m) => {
                    m.set(link.data, 'text', 'Label');
                });
            },
            contextMenu: node_menu(),
            selectionChanged: function (line) {
                var nodeData = line.data;
                var s_type = 9099;
                if (line.isSelected) {

                } else {

                }
            },
        })
            .bindTwoWay('points')
            .add(
                new go.Shape({
                    isPanelMain: true,
                    strokeWidth: 8,
                    stroke: 'transparent',
                    name: 'HIGHLIGHT',
                }),
                new go.Shape({ isPanelMain: true, strokeWidth: 2 })
                    .bind("stroke", function (data) {
                        var link = "link";
                        if (data.todo == 9) {
                            link = "linked";
                        }
                        return opt.diagram.themeManager.findValue(link, 'colors', this.currentTheme);
                    }),

                new go.Shape({ toArrow: 'standard', strokeWidth: 0, scale: 1.5 })
                    .bind("fill", function (data) {
                        var link = "link";
                        if (data.todo == 9) {
                            link = "linked";
                        }
                        return opt.diagram.themeManager.findValue(link, 'colors', this.currentTheme);
                    }),
                new go.Panel('Auto', { visible: false })
                    .bind('visible', 'text', (t) => typeof t === 'string' && t.length > 0) // only shown if there is text
                    .add(
                        new go.Shape('Ellipse', { strokeWidth: 0 }).theme('fill', 'div', null, null, (c) => {
                            return new go.Brush(go.BrushType.Radial, {
                                colorStops: new go.Map([
                                    { key: 0, value: c },
                                    { key: 0.5, value: `${c}00` },
                                ]),
                            });
                        }),
                        new go.TextBlock({
                            name: 'LABEL',
                            font: '9pt Figtree, sans-serif',
                            margin: 3,
                            editable: true,
                        })
                            .theme('stroke', 'bgText')
                            .bindTwoWay('text')
                    )
            );

        opt.diagram.toolManager.linkingTool.temporaryLink.routing = go.Routing.Orthogonal;
        opt.diagram.toolManager.relinkingTool.temporaryLink.routing = go.Routing.Orthogonal;

        form_load($object);
    }

    function defineFigures() {
        go.Shape.defineFigureGenerator('Judge', (shape, w, h) => {
            const geo = new go.Geometry();
            const fig = new go.PathFigure(w * 0.15, 0, true);
            geo.add(fig);
            fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.85, 0));
            fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.5 * h));
            fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.85, h));
            fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.15, h));
            fig.add(new go.PathSegment(go.SegmentType.Line, 0, 0.5 * h).close());
            geo.spot1 = new go.Spot(0.15, 0);
            geo.spot2 = new go.Spot(0.85, 1);
            return geo;
        });

        go.Shape.defineFigureGenerator('File', (shape, w, h) => {
            const geo = new go.Geometry();
            const fig = new go.PathFigure(0, 0, true);
            geo.add(fig);

            var w_ = (w > 100 ? (w - 40) : 0.75 * w);
            var h_ = (h > 50 ? 20 : 0.25 * h);

            fig.add(new go.PathSegment(go.SegmentType.Line, w_, 0));
            fig.add(new go.PathSegment(go.SegmentType.Line, w, h_));
            fig.add(new go.PathSegment(go.SegmentType.Line, w, h));
            fig.add(new go.PathSegment(go.SegmentType.Line, 0, h).close());
            const fig2 = new go.PathFigure(w_, 0, false);
            geo.add(fig2);
            // The Fold
            fig2.add(new go.PathSegment(go.SegmentType.Line, w_, h_));
            fig2.add(new go.PathSegment(go.SegmentType.Line, w, h_));
            geo.spot1 = new go.Spot(0, 0.25);
            geo.spot2 = go.Spot.BottomRight;
            return geo;
        });
    }

    /*
        主信息：
            9000 主信息
        点：
            9001 Start 开始节点
            9002 Return 退回节点

            9005 Exec 执行节点
            9007 Proc 程序节点
            9006 Judge 判断节点

            9008 Cancle 取消节点
            9009 End 结束节点

            9010 Comment 文档节点
        线
            9099 线
    */
    function load($object, value) {
        var opt = options($object);
        if (value === undefined) {
            value = opt.value;
        } else {
            if (value === null) {
                value = {};
            }
            opt.value = value;
        }

        var json_ = typeof value == "string" ? JSON.parse(value) : value;
        if (json_.node === undefined) {
            json_.node = [];
        }
        if (json_.link === undefined) {
            json_.link = [];
        }
        if (json_.info === undefined) {
            json_.info = {};
        }
        opt.value = json_;

        if (!(opt.$jsonview === undefined)) {
            opt.$jsonview.val($.jsonFormat(opt.value));
        }
        var j_ = {
            "class": "GraphLinksModel",
            "linkFromPortIdProperty": "fromPort",
            "linkToPortIdProperty": "toPort",
        };

        var nodes = [];
        if (json_.info.wfstate == 0 || json_.info.wfstate == 1) {
            for (var i = 0; i < json_.node.length; i++) {
                if (json_.node[i].class != 2) {
                    nodes.push(JSON.parse(JSON.stringify(json_.node[i])));
                }
            }
        }
        else if (json_.info.wfstate == 8 || json_.info.wfstate == 9) {
            for (var i = 0; i < json_.node.length; i++) {
                if (json_.node[i].todo == 9) {
                    nodes.push(JSON.parse(JSON.stringify(json_.node[i])));
                }
            }
        } else {
            nodes = json_.node;
        }

        var lines = [];
        for (var i = 0; i < json_.link.length; i++) {
            if (typeof json_.link[i].points === "string") {
                json_.link[i].points = JSON.parse("[" + json_.link[i].points + "]");
            }
            var hasFromNode = false;
            var hasToNode = false;
            for (var j = 0; j < nodes.length; j++) {
                if (json_.link[i].from == nodes[j].key) {
                    hasFromNode = true;
                }
                if (json_.link[i].to == nodes[j].key) {
                    hasToNode = true;
                }

                if (hasFromNode && hasToNode) {
                    break;
                }
            }

            if (hasFromNode && hasToNode) {
                if (json_.info.wfstate == 8 || json_.info.wfstate == 9) {
                    if (json_.link[i].todo == 9) {
                        lines.push(JSON.parse(JSON.stringify(json_.link[i])));
                    }
                } else {
                    lines.push(JSON.parse(JSON.stringify(json_.link[i])));
                }
            }
        }

        j_.nodeDataArray = nodes;
        j_.linkDataArray = lines;

        opt.diagram.model = go.Model.fromJson(j_);
    }

    function getModel($object) {
        var opt = options($object);
        return opt.value;
    }

    function submit($object, e, node) {
        var opt = options($object);

        var data = $object.yqFlowView("getValue");

        var pp = submit_titles(opt, data, node)

        var submit_user = pp.submit_user;
        var mmdLists = pp.mmdLists;
        var params = pp.params;
        var titles = pp.titles;

        var modal = `
                        <table _n="_tb">
	<tbody style="vertical-align: top;">`+ (submit_user.self != submit_user.id ?
                `<tr style="color: #ff0000;"><td><lable>待办人</lable></td><td><lable>` + submit_user.name + `</lable></td></tr>` :
                ``) + `
	<tr>
			<td>
				<lable id="lbl_mmdId">审批动作
				</lable>
			</td>
			<td>
				<select style="width: 200px" id="txt_mmdId">
				</select>
			</td>
		</tr>
		<tr>
			<td>
				<lable id="lbl_mmdDesc">审批意见
				</lable>
			</td>
			<td>
				<textarea style="height: 100px; width: 302px;" id="txt_mmdDesc">
				</textarea>
			</td>
		</tr>`+ (params.titles.length > 0 ?
                `<tr>
			<td>
				<lable id="lbl_params">扩展信息
				</lable>
			</td>
			<td>
				<select style="width: 300px" id="txt_params">
				</select>
			</td>
		</tr>`: "") + `
	</tbody>
</table>
                        `;

        var point = e.viewPoint;
        var prevent_e = {
            $object: e,
            clientX: point.x,
            clientY: point.y,
        };

        prevent_e.options = {
            beforeChange: function (row, callback) {
                //console.log("beforeChange", row);
                if (row.mmdId === null) {
                    $.yqMessager("error", "没有选择审批动作，不能提交。");
                    callback(false, row);
                } else {
                    if (!row.mmdDesc || row.mmdDesc.length === 0) {
                        delete row.mmdDesc;
                    }
                    if (!row.params || row.params.length === 0) {
                        delete row.params;
                    }

                    row["key"] = node.key;
                    var res = $_yqFlow.submitLines(data, row);
                    if (res.error == 0) {
                        row.user = submit_user;
                        callback(true, row);
                    } else {
                        $.yqMessager("error", res.info);
                        callback(false, row);
                    }
                }
            }
        };

        var _heiget = (params.titles.length > 0 ? 240 : 200);
        if (submit_user.self != submit_user.id) {
            _heiget += 30;
        }

        var _pops = {
            prevent_e: prevent_e,
            mdiinfo: $.yqGetWindParams(),
            width: 412,
            height: _heiget,
            horizontalAlign: "none",    //left,right,center,none
            verticalAlign: "none",      //top,bottom,center,none

            titles: titles,
            model: modal,
            action: "add",
            row: pp.row,
            isEdit: true,
            loadDefault: false,   //加载默认值
            blankTag: "*",     //值不能为空，标题附加标记
            removeUnUse: false,

            ok_text: "确定提交",
            no_text: "不提交",

            callback: function (_row) {
                submit_run($object, _row);
            }
        };

        if (window.top == window.self) {
            $.yqFormPopEdit(_pops);
        }
        else {
            window.top.$.yqFormPopEdit(_pops);
        }
    }

    //流程打印
    function printDiagram($object) {
        var opt = options($object);
        var svgWindow = window.open();
        if (!svgWindow) return;  // failure to open a new Window
        var printSize = new go.Size(700, 960);
        var bnds = opt.diagram.documentBounds;
        var x = bnds.x;
        var y = bnds.y;
        while (y < bnds.bottom) {
            while (x < bnds.right) {
                var svg = opt.diagram.makeSvg({ scale: 1.0, position: new go.Point(x, y), size: printSize });
                svgWindow.document.body.appendChild(svg);
                x += printSize.width;
            }
            x = bnds.x;
            y += printSize.height;
        }

        setTimeout(function () {
            svgWindow.print()
            svgWindow.close();
        }, 1);
    }

    //保存json
    function saveDiagram($object, filename) {
        var text = $.jsonFormat(getModel($object));

        var blob = new Blob([text], { type: "text/plain;charset=utf-8" });
        var url = URL.createObjectURL(blob);
        var link = document.createElement('a');
        link.href = url;
        link.download = (filename === undefined ? "flow.json" : filename);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }

    function loadFile($object) {
        var opt = options($object);
        if (opt.fileselect === undefined) {
            var input = document.createElement('input');
            input.type = "file";
            input.accept = ".json,.txt";
            input.style = "display: none";
            document.body.appendChild(input);
            input.addEventListener('change', function (e) {
                var file = e.target.files[0]; // 获取选中的文件  
                if (file) {
                    var fileType = file.type; // 获取文件类型  
                    var allowedTypes = ['text/plain', 'application/json']; // 允许的文件类型  
                    if (allowedTypes.includes(fileType)) {
                        var reader = new FileReader();
                        reader.onload = function (e) {
                            try {
                                var _j = JSON.parse(e.target.result);
                                load($object, _j);
                            }
                            catch (err) {
                                console.error("filejson", err);
                                $.yqMessager("error", "内容格式错误。");
                            }
                        };
                    }
                }
            });

            opt.fileselect = input;
        }
        opt.fileselect.click();
    }
    //--- 流程图显示模式 end -----------------------

    //--- 表格显示模式 begin -----------------------
    function init_html_2($object) {
        var opt = options($object);

        /*
            加载css样式
        */
        $.yqAddCSS(`
:root {
    --default-color: #cccccc;
    --todo-color: #ffab3f;
    --comp-color: #4bbb4b;
    --cancle-color: #ee1212;

    --default-bk-color: #f7faff;
    --todo-bk-color: #e6edf7;
  }

  .yqflow_sp {
    font-size: 13px;
    width:100%;
  }

  .yqflow_sp .title td{
    padding:2px 5px;
  }
  .yqflow_sp .title span{
    font-size: 10px;
    padding-right: 5px;
  
  }
  .yqflow_sp .title span.name{
    color: var(--todo-color);
  }
  .yqflow_sp .title span.wfstate{
    color: var(--comp-color);
  }

  .yqflow_sp .title span.s_time{
    color: var(--default-color);
  }

  .yqflow_sp .title span.e_time{
    color: var(--cancle-color);
  }

  
  .yqflow_sp .td1 {
    width: 50px;
    text-align: center;
  }

  .yqflow_sp .td1 span {
    padding: 4px 10px 6px 10px;
    border-radius: 50%;
    overflow: hidden;
    color: white;
    font-size: 13px;
  }

  .yqflow_sp tr.default .td1 span {
    background-color: var(--default-color);
  }

  .yqflow_sp tr.todo .td1 span {
    background-color: var(--todo-color);
  }

  .yqflow_sp tr.comp .td1 span {
    background-color: var(--comp-color);
  }

  .yqflow_sp .td2 {
    min-width: 100px;
    max-width: 160px;
    font-size: 13px;
  }

  .yqflow_sp .td2 .state {
    color: rgb(71, 71, 71);
  }

  .yqflow_sp .td2 .name {
    color: rgb(71, 71, 71);
  }

  .yqflow_sp .td3 {
    width: 30px;
  }

  .yqflow_sp .td3 div {
    width: 20px;
    height: 20px;
    position: relative;
    border-radius: 50%;
  }

  .yqflow_sp tr.default .td3 div {
    border: 10px solid var(--default-color);
  }

  .yqflow_sp tr.todo .td3 div {
    border: 6px solid var(--todo-color);
  }

  .yqflow_sp tr.comp .td3 span {

    position: relative;
    border-radius: 50%;
    background-color: var(--comp-color);
    padding: 0px 5px;
    font-size: 14px;
    font-weight: 900;
    color: white;
  }

  .yqflow_sp .td4 {
    width: 12px;
    padding: 0;
    margin: 0;
    text-align: right;
  }

  .yqflow_sp .td4 span {
    font-size: 40px;
  }

  .yqflow_sp .td4 span {
    font-size: 40px;
  }

  .yqflow_sp tr.default .td4 span,
  .yqflow_sp tr.comp .td4 span {
    color: var(--default-bk-color);
  }

  .yqflow_sp tr.todo .td4 span {
    color: var(--todo-bk-color);
  }

  .yqflow_sp .td5{
    min-width: 250px;
  }

  .yqflow_sp .td5 .inner {
    margin: 3px 3px 3px -1px;
    padding: 0px 7px;
    font-size: 12px;
  }

  .yqflow_sp .td5 .line{
     padding: 2px;
  }

  .yqflow_sp .td5 .line p{
    line-height: 7px;
  }

  .yqflow_sp tr.default .td5 div,
  .yqflow_sp tr.comp .td5 div {
    background-color: var(--default-bk-color);
  }

  .yqflow_sp tr.todo .td5 div {
    background-color: var(--todo-bk-color);
  }

  /*
    选择当前审批
  */
  .yqflow_sp .inner a.todo{
    padding: 2px 5px;
  }

  .yqflow_sp .submit_edit td{
    font-size: 13px;
    padding: 4px;
  }

  .yqflow_sp .div_mmdId a{
      margin: 0 3px;
  }

  .yqflow_sp .div_mmdId .l-btn-left,
  .yqflow_sp .submit .l-btn-left{
    padding: 3px 10px;
  }

  .yqflow_sp .div_mmdId .btn1 .l-btn-left,
  .yqflow_sp .div_mmdId .btn2 .l-btn-left{
    color: #f7faff;
    background-color: var(--todo-color);
  }

  .yqflow_sp .div_mmdId .btn0 .l-btn-left{
    color: #f7faff;
    background-color: var(--cancle-color);
  }

  .yqflow_sp .div_mmdId .btn8 .l-btn-left{
    color: #f7faff;
    background-color: var(--default-color);
  }  
        `, `yqflow_sp`);

        $object.empty();
        $object.append(`
            <table class="yqflow_sp">
                <tr class="title">
                    <td style="width:95px;"><span class="fa fa-stop name"></span>流程名称：</td>
                    <td class="name">name</td>
                    <td style="width:95px;"><span class="fa fa-stop wfstate"></span>执行状态：</td>
                    <td class="wfstate">wfstate</td>
                </tr> 
                <tr class="title">
                    <td><span class="fa fa-stop s_time"></span>开始时间：</td>
                    <td class="s_time">s_time</td>
                    <td><span class="fa fa-stop e_time"></span>结束时间：</td>
                    <td class="e_time">e_time</td>
                </tr>
                <tr>
                    <td colspan="4" style="padding: 0;"><div class="inner"></div></td>
                </tr> 
            </table>`);

        opt.$info_name = $object.find("td.name");
        opt.$info_wfstate = $object.find("td.wfstate");
        opt.$info_s_time = $object.find("td.s_time");
        opt.$info_e_time = $object.find("td.e_time");
        opt.$inner = $object.find(".inner");

        opt.$inner.panel({
            width: opt.width,
            height: opt.height - 43,
            border: false,
            bodyCls: ""
        });

        form_load($object);
    }

    function load_2($object, value) {
        var opt = options($object);
        if (value === undefined) {
            value = opt.value;
        } else {
            if (value === null) {
                value = {};
            }
            opt.value = value;
        }

        if (!(opt.$submit === undefined)) {
            opt.$submit.yqFormEdit("destroy");
            opt.$inner.empty();
        }

        opt.$info_name.html(value.info.name);
        opt.$info_wfstate.html($_yqFlow.formatWfState(value.info.wfstate));
        opt.$info_s_time.html(value.info.s_time === undefined ? "" : value.info.s_time);
        opt.$info_e_time.html(value.info.e_time === undefined ? "" : value.info.e_time);

        var $tb = $('<table style="width:' + (opt.width - 10) + 'px;"></table>');
        opt.$inner.panel("body").append($tb);

        var nodes = [];

        var todos = [];
        for (var i = 0; i < value.node.length; i++) {
            if (value.node[i].class == 1 ||
                value.node[i].class == 2 ||
                value.node[i].class == 5 ||
                value.node[i].class == 8 ||
                value.node[i].class == 9
            ) {
                if (((value.info.wfstate == 0 || value.info.wfstate == 1) &&
                    value.node[i].class != 2) ||
                    (value.info.wfstate == 2 || value.info.wfstate == 5) ||
                    ((value.info.wfstate == 8 || value.info.wfstate == 9) &&
                        value.node[i].todo == 9)) {
                    var node = JSON.parse(JSON.stringify(value.node[i]));

                    if (!(value.info.wfstate == 8 || value.info.wfstate == 9)) {
                        if (node.todo === 1) {
                            if ((opt.type == 0 || opt.type == 1 || opt.admin) || $_yqFlow.checkPower(node, opt.users)) {
                                todos.push(node);
                            }
                        }
                    }

                    nodes.push(node);
                }
            }
        }

        for (var i = 0; i < nodes.length; i++) {
            var node = nodes[i];
            var $tr = $('<tr class="' + (node.todo === undefined ? "default" : (node.todo == 1 ? "todo" : "comp")) + '"></tr>');
            $tb.append($tr);

            $tr.append('<td class="td1"><span>' + node.category[0].toLowerCase() + '</span></td>');

            var $td2 = $('<td class="td2"></td>');
            $tr.append($td2);
            $td2.append('<span class="state">' + $_yqFlow.formatNodeState(node.todo === undefined ? 0 : node.todo) + '</span>');
            $td2.append('<br/>');
            $td2.append('<span class="name">' + node.text + '</span>');

            var $td3 = $('<td class="td3"></td>');
            $tr.append($td3);
            if (node.todo === 9) {
                $td3.append('<span>✓</span>');
            } else {
                $td3.append('<div></div>');
            }

            $tr.append('<td class="td4"><span class="fa fa-caret-left"></span></td>');

            var $td5 = $('<td class="td5"><div class="inner"></div></td>');
            $tr.append($td5);
            $td5 = $td5.find("div");
            var td5 = "";
            if (node.class == 1 || node.class == 2 || node.class == 5) {
                var comps = $_yqFlow.submitData(value, node);
                for (var j = 0; j < comps.length; j++) {
                    td5 += '<div class="line">';
                    td5 += '    <p class="comp1_' + comps[j].mmdId + '">审批人:<span class="user">' + (comps[j].user.name) + '</span><span class="mmd">' + (comps[j].mmdId) + '</span><p>';
                    if (!(comps[j].mmdDesc === undefined ||
                        comps[j].mmdDesc === null ||
                        comps[j].mmdDesc === "")) {
                        td5 += '    <p class="comp2">审批意见:<span>' + (comps[j].mmdDesc) + '</span><p>';
                    }
                    td5 += '    <p class="comp2">审批时间:<span>' + (comps[j].time) + '</span><p>';
                    td5 += '</div>';
                }

                if (node.todo === undefined) {
                    if (node.roleIsEdit || node.users.length == 0) {
                        td5 += '<div class="line">';
                        td5 += '   <input style="width: 100%;" type="text"/>';
                        td5 += '</div>';
                    } else {
                        var users = "";
                        for (var j = 0; j < node.users.length; j++) {
                            if (node.users[j].mmdId === undefined) {
                                users += (users == "" ? "" : "、") + node.users[j].name;
                            }
                        }
                        if (users != "") {
                            td5 += '<div class="line">';
                            td5 += '    <p class="">审批人:' + users + '</p>';
                            td5 += '</div>';
                        }
                    }
                } else if (node.todo === 1) {
                    var users = "";
                    for (var j = 0; j < node.users.length; j++) {
                        if (node.users[j].mmdId === undefined) {
                            users += (users == "" ? "" : "、") + node.users[j].name;
                        }
                    }
                    if (users != "") {
                        td5 += '<div class="line">';
                        td5 += '    <p class="">审批人:' + users + '</p>';
                        td5 += '    <p class="">开始时间:' + node.s_time + '</p>';
                        td5 += '</div>';
                    }
                }
            }
            var $td5_2 = $(td5)
            $td5.append($td5_2);

            var $input = $td5_2.find("input");
            if ($input.length > 0) {
                $input.yqNForeignKey({
                    node: node,
                    panelWidth: 600,
                    panelHeight: 400,
                    displayType: 2,
                    dbname: "yqbase",
                    tbname: "hr_user",
                    tempno: 100,
                    addWhere: "",
                    order: "name",
                    isPage: true,
                    pageSize: 10,
                    pageNo: 1,
                    valueMember: "sid",
                    displayMember: "name",
                    isSeek: true,
                    seekNo: 100,
                    seekModeW: 800,
                    seekModeH: 600,
                    seekSimple: true,
                    seekSimpleDDLW: 150,
                    seekSimpleTxtW: 200,
                    enable: true,
                    beforeBindingTitle: function (columns, callback) {
                        callback(columns);
                    },
                    onClickRow: function (rows) {
                        var users = [];
                        if (!(rows === null)) {
                            for (var j = 0; j < rows.length; j++) {
                                users.push({
                                    id: rows[j].sid,
                                    name: rows[j].name
                                });
                            }
                        }
                        var _node = $(this).yqNForeignKey("options").node;
                        //0-本地测试,1-服务端测试,2-执行流程
                        if (opt.type == 0) {
                            $_yqFlow.localUppUser(opt.value, _node.key, users, function (wf_data) {
                                opt.value = wf_data;
                            });
                        } else if (opt.type == 1 || opt.type == 2) {
                            $_yqFlow.wfUppUser(opt.initId, _node.key, users, (opt.type === 1), function (res) {
                                if(res.error == 0){
                                    opt.value = res.wf;
                                }else{
                                    $.yqMessager("error", res.info);
                                }
                            });
                        }
                    },  //选择行事件 null：为空
                });

                var users = "";
                for (var j = 0; j < node.users.length; j++) {
                    users += (users == "" ? "" : ",") + node.users[j].id;
                }
                if (users != "") {
                    $input.yqNForeignKey("setValue", users);
                }
            }

            if (todos.length > 1) {
                for (var j = 0; j < todos.length; j++) {
                    if (todos[j].key == node.key) {
                        var $btn = $('<a class="todo"></a>');
                        $td5.append($btn);
                        $btn.linkbutton({
                            text: (j == 0 ? "当前" : "") + "审批",
                            plain: true,

                            node: node,
                            onClick: function () {
                                var node = $(this).linkbutton("options").node;
                                submit_2($object, node);
                            }
                        });

                        break;
                    }
                }
            }
        }

        if (todos.length > 0 || opt.admin) {
            var $tr = $("<tr></tr>");
            $tb.append($tr);
            var $td = $('<td colspan="5"></td>');
            $tr.append($td);
            opt.$submit = $('<div class="submit"></div>');
            $td.append(opt.$submit);
        }

        if (todos.length == 0 && opt.admin) {
            opt.$submit.css({
                "text-align": "center"
            });
            var $btn = $('<a class="btn"></a>');
            opt.$submit.append($btn);
            $btn.linkbutton({
                text: "查看流程信息",
                onClick: function () {
                    wf_view_2($object);
                }
            });
        }


        if (todos.length > 0) {
            submit_2($object, todos[0]);
        }
    }

    function submit_2($object, node) {
        var opt = options($object);

        var data = $object.yqFlowView("getValue");

        var pp = submit_titles(opt, data, node)

        var submit_user = pp.submit_user;
        var mmdLists = pp.mmdLists;
        var params = pp.params;
        var titles = pp.titles;

        var w_ = (opt.width - 100);
        if (w_ > 350) {
            w_ = 350;
        } else if (w_ < 250) {
            w_ = 250;
        }

        var modal = `
<table _n="_tb" class="submit_edit">
	<tbody style="vertical-align: top;">`+ (submit_user.self != submit_user.id ?
                `<tr style="color: #ff0000;"><td><lable>待办人</lable></td><td><lable>` + submit_user.name + `</lable></td></tr>` :
                ``) + `
		<tr>
            <td  colspan="2">`+ node.text + `【审批】
            </td>
        </tr>
        <tr>
			<td>审批意见</td>
			<td>
				<textarea style="height: 60px; width: `+ w_ + `px;" id="txt_mmdDesc">
				</textarea>
			</td>
		</tr>`+ (params.titles.length > 0 ?
                `<tr>
			<td>扩展信息</td>
			<td>
				<select style="width: `+ w_ + `px" id="txt_params">
				</select>
			</td>
		</tr>`: "") + `
        <tr>
			<td colspan="2" style="text-align: center;">
			    <div class="div_mmdId">
				</div>
			</td>
		</tr>
	</tbody>
</table>`;

        opt.$submit.yqFormEdit({
            titles: titles,
            model: modal,
            action: "add",
            row: pp.row,
            loadDefault: false,   //加载默认值
            isEdit: true,
            blankTag: "*",     //值不能为空，标题附加标记
            controlType: 1,    //默认显示类型 1-textbox模式  2-div模式
            removeUnUse: false, //是否移除未使用的字段
            addClass: "yqflow_submit",  //附加样式
            beforeBindingTitle: function (titles, callback) {
                callback(titles);
            }, //标题绑定前
            afterBindingTitle: function () {
                var $div_mmdId = $(this).find(".div_mmdId");
                for (var i = 0; i < mmdLists.length; i++) {
                    var $btn = $('<a class="btn' + mmdLists[i].no + '"></a>');
                    $div_mmdId.append($btn);
                    $btn.linkbutton({
                        text: mmdLists[i].name,
                        mmdList: mmdLists[i],

                        onClick: function () {
                            var mmdList = $(this).linkbutton("options").mmdList;
                            var row = opt.$submit.yqFormEdit("getRow");
                            row.mmdId = mmdList.no;
                            row.mmdName = mmdList.name;

                            if (!row.mmdDesc || row.mmdDesc.length === 0) {
                                delete row.mmdDesc;
                            }
                            if (!row.params || row.params.length === 0) {
                                delete row.params;
                            }

                            row["key"] = node.key;
                            row.user = submit_user;

                            console.log("row", row);

                            submit_run($object, row)
                        }
                    });
                }

                if (opt.admin) {
                    var $btn = $('<a class="btn"></a>');
                    $div_mmdId.append($btn);
                    $btn.linkbutton({
                        text: "查看流程信息",
                        onClick: function () {
                            wf_view_2($object);
                        }
                    });
                }
            },   //标题绑定后
            beforeSetRow: function (row, callback) {
                callback(row);
            },  //数据加载前
            afterSetRow: function (row) { },  //数据加载后
            endEditing: function (row) {   //ok.....

            }
        })
    }

    function wf_view_2($object) {
        var opt = options($object);

        var prevent_e = $.getPreventDefault($object);
        prevent_e.clientY -= ($object.height() + 2);

        _w = opt.width;
        _h = opt.height;

        var _pops = {
            prevent_e: prevent_e,
            mdiinfo: $.yqGetWindParams(),
            width: _w,
            height: _h,
            horizontalAlign: "none",
            verticalAlign: "none",
            types: ["json"],
            type: "json",
            value: JSON.stringify(opt.value, null, 2),
            isEdit: false,
            goDocEnd: false,
        };

        if (window.top == window.self) {
            $.yqCodePopEdit(_pops);
        }
        else {
            window.top.$.yqCodePopEdit(_pops);
        }
    }

    //--- 表格显示模式 end -------------------------


    function submit_titles(opt, data, node) {
        //--提交人---------------------------------
        var submit_user = null
        if (opt.type == 0 || opt.type == 1) {
            submit_user = $_yqFlow.submitUser_test(node);
        } else if (opt.type == 2 && opt.admin) {
            submit_user = $_yqFlow.submitUser_admin(node, opt.users);
        }
        else if (opt.type == 2 && !opt.admin) {
            submit_user = $_yqFlow.submitUser(node, opt.users);
        }

        if (submit_user === null) {
            $.yqMessager("error", "没有审批人，不能提交审批。");
            return null;
        }
        console.log(submit_user);
        //-----------------------------------------

        var mmdLists = $_yqFlow.mmdLists(data, node.key);
        console.log("mmdLists", mmdLists);
        if (mmdLists.length == 0) {
            $.yqMessager("error", "没有路径，不能提交。");
            return {};
        }

        var params = $_yqFlow.nodeparams(data, node);

        var titles = [
            {
                "name": "mmdId",
                "ui_title": "审批动作",
                "ui_type": 6,
                "ui_width": 280,
                "ui_visible": true,
                "ui_readonly": false,
                "ui_mask": {
                    "default": 1,
                    "blank": false,
                    "lists": mmdLists,
                    "displayType": 2,
                    "valueMember": "sid",
                    "displayMember": "sid",
                    "isPage": true,
                    "pageSize": 10,
                    "order": "sid",
                    "panelWidth": 400,
                    "panelHeight": 260,
                    "seekSimple": true,
                    "seekSimpleDDLW": 120,
                    "seekSimpleTxtW": 150,
                    "isSeek": true,
                    "seekNo": -1,
                    "seekModeW": 800,
                    "seekModeH": 600
                }
            },
            {
                "name": "mmdDesc",
                "ui_title": "审批意见",
                "ui_type": 5,
                "ui_width": 80,
                "ui_visible": true,
                "ui_readonly": false,
                "ui_mask": {
                    "default": "base",
                    "types": [
                        "base"
                    ],
                    "editModeW": 400,
                    "editModeH": 300,
                    "displayType": 2,
                    "valueMember": "sid",
                    "displayMember": "sid",
                    "isPage": true,
                    "pageSize": 10,
                    "order": "sid",
                    "panelWidth": 400,
                    "panelHeight": 260,
                    "seekSimple": true,
                    "seekSimpleDDLW": 120,
                    "seekSimpleTxtW": 150,
                    "isSeek": true,
                    "seekNo": -1,
                    "seekModeW": 800,
                    "seekModeH": 600
                }
            }
        ];

        if (params.titles.length > 0) {
            titles.push({
                "name": "params",
                "ui_title": "扩展信息",
                "ui_type": 17,
                "ui_width": 80,
                "ui_visible": true,
                "ui_readonly": false,
                "ui_mask": {
                    "default": params.row,
                    "param": {
                        "titles": params.titles,
                        "model": []
                    },
                    "editType": 1,
                    "editModeW": 450,
                    "editModeH": 220,
                    "modeNo": -1
                }
            });
        }

        return {
            submit_user: submit_user,
            mmdLists: mmdLists,
            titles: titles,
            params: params,
            row: {
                mmdId: mmdLists.length == 0 ? -1 : mmdLists[0].no,
                mmdDesc: '',
                params: $.yqGetDefaultRow(params.titles)
            },
        }
    }

    function submit_run($object, _row) {
        var opt = options($object);
        var data = $object.yqFlowView("getValue");

        opt.beforeSubmit.call($object, _row, function (tf, row) {
            if (tf) {
                if (opt.type == 0) {//本地测试
                    $_yqFlow.localtest(data, row, function (res) {
                        submit_after(res);
                    });
                } else if (opt.type == 1) {//服务端测试
                    $_yqFlow.wfSubmit(data, row, function (res) {
                        submit_after(res);
                    }, true);
                } else if (opt.type == 2) { //执行流程
                    row.stamp = data.info.stamp;
                    $_yqFlow.wfSubmit(opt.initId, row, function (res) {
                        submit_after(res);
                    }, false);
                }
            }
        })

        function submit_after(res) {
            if (res.error == 0) {
                if (opt.isFlow) {
                    load($object, res.wf);
                } else {
                    load_2($object, res.wf);
                }
            } else {
                $.yqMessager("error", res.info + "[" + res.error + "]");
            }

            opt.afterSubmit.call($object, res);
        }
    }

})(jQuery);

//工作流处理程序
var $_yqFlow = {
    //日期格式化
    formatDate: function (date) {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const seconds = String(date.getSeconds()).padStart(2, '0');

        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
    //开始节点
    start: function (data) {
        for (var i = 0; i < data.node.length; i++) {
            if (data.node[i].class == 1) {
                return data.node[i];
            }
        }
        return null;

    },
    //根据key返回节点
    node: function (data, key) {
        for (var i = 0; i < data.node.length; i++) {
            if (data.node[i].key === key) {
                return data.node[i];
            }
        }
        return null;
    },
    //获取节点执行连线
    toLines: function (data, from) {
        var links = [];
        for (var i = 0; i < data.link.length; i++) {
            if (data.link[i].from == from) {
                links.push(data.link[i]);
            }
        }
        return links;
    },
    //获取节点执行动作
    mmdLists: function (data, from) {
        var links = $_yqFlow.toLines(data, from);
        if (links.length == 0) {
            return [];
        }

        var list = [];
        var mmdIds = [1, 2, 0, 8]
        for (var i = 0; i < mmdIds.length; i++) {
            for (var j = 0; j < links.length; j++) {
                if (links[j].mmdId === mmdIds[i]) {
                    list.push({
                        no: links[j].mmdId,
                        name: links[j].text
                    });
                    break;
                }
            }
        }

        return list;
    },
    //获取节点连线动作名称
    mmdName: function (data, from, mmdId) {
        var links = $_yqFlow.toLines(data, from);
        if (links.length == 0) {
            return null;
        }

        for (var j = 0; j < links.length; j++) {
            if (links[j].mmdId === mmdId) {
                return links[j].text;
            }
        }

        return null;
    },
    //获取节点输入参数
    nodeparams: function (data, node) {
        if (node.params === undefined || node.params == null) {
            return {
                titles: [],
                row: {}
            }
        }

        var titles = [];
        var row = {};
        for (var i = 0; i < node.params.length; i++) {
            for (j = 0; j < data.info.params.length; j++) {
                if (node.params[i].name == data.info.params[j].name) {
                    titles.push({
                        "name": data.info.params[j].name,
                        "ui_title": data.info.params[j].desc,
                        "ui_type": data.info.params[j].type,
                        "ui_width": 80,
                        "ui_visible": true,
                        "ui_readonly": false,
                        "ui_mask": data.info.params[j].ui_mask
                    });

                    row[data.info.params[j].name] = (data.info.params[j].value === undefined ? null : data.info.params[j].value);
                    break;
                }
            }
        }

        return {
            titles: titles,
            row: row
        }
    },
    //获取执行节点
    todos: function (data, from, mmdId) {
        var links = [];
        for (var i = 0; i < data.link.length; i++) {
            if (data.link[i].from == from &&
                data.link[i].mmdId == mmdId) {
                links.push(data.link[i]);
            }
        }
        return links;
    },
    //线表达式校验
    evalTodos: function (todos, parmas) {
        if (todos.length == 1) {
            return todos;
        }

        var todos_ = [];
        for (var i = 0; i < todos.length; i++) {
            if ($_yqFlow.expression(todos[i].expression, parmas)) {
                todos_.push(todos[i]);
            }
        }

        return todos_;
    },
    //校验表达式
    expression: function (exp_str, parmas) {
        if (!(typeof parmas == "object" && typeof exp_str == "string")) {
            return true;
        }

        if (parmas.length == 0 || exp_str == "") {
            return true;
        }

        var context = {};
        for (var i = 0; i < parmas.length; i++) {
            context[parmas[i].name] = parmas[i].value === undefined ? (parmas[i].ui_mask.default === undefined ? null : parmas[i].ui_mask.default) : parmas[i].value;
        }

        // 去掉 @ 前缀
        var cleanedExpression = exp_str.replace(/@\b/g, '');

        // 使用 Function 构造函数动态求值
        try {
            var func = new Function(...Object.keys(context), 'return ' + cleanedExpression);
            return func(...Object.values(context));
        } catch (error) {
            console.error("表达式求值错误:", error);
            return false;
        }
    },
    //获取提交路径
    submitLines: function (data, submit) {
        if (submit.params === undefined || submit.params === null) {
            submit.params = [];
        }
        if (data.info.params === undefined || data.info.params === null) {
            data.info.params = []
        }

        var todos = $_yqFlow.todos(data, submit.key, submit.mmdId);
        if (todos.length == 0) {
            return {
                error: 9,
                info: "没有路径[mmdId=" + submit.mmdId + "]，不能提交。"
            };
        }
        var params = [];
        for (var i = 0; i < data.info.params.length; i++) {
            var param = deepClone(data.info.params[i]);
            if (submit.params.hasOwnProperty(param.name)) {
                param.value = submit.params[param.name];
            }
            params.push(param);
        }



        //线表达式计算
        var eval_todos = $_yqFlow.evalTodos(todos, params);

        //console.log(data, submit, todos, eval_todos);
        //console.log(eval_todos);
        if (eval_todos.length == 0) {
            return {
                error: 9,
                info: "没有路径[mmdId=" + submit.mmdId + ",有" + todos.length + "条路径，参数校验都为false]，不能提交。"
            };
        }

        return {
            error: 0,
            todos: eval_todos,
            params: params
        };


        function deepClone(obj) {
            if (obj === null || typeof obj !== 'object') {
                return obj;
            }
            if (Array.isArray(obj)) {
                var arr = [];
                for (var i = 0; i < obj.length; i++) {
                    arr[i] = deepClone(obj[i]);
                }
                return arr;
            }
            var copy = {};
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    copy[key] = deepClone(obj[key]);
                }
            }
            return copy;
        }

    },

    //获取节点审批意见
    submitData: function (data, node) {
        var lists = [];
        if (data.submit === undefined) {
            return lists;
        }

        for (var i = 0; i < data.submit.length; i++) {
            if (data.submit[i].key == node.key) {
                lists.push(data.submit[i]);
            }
        }

        return lists;
    },

    //校验当前节点是否有审批权限
    checkPower: function (node, users) {
        return $_yqFlow.submitUser(node, users) === null ? false : true;
    },
    //提交人
    submitUser: function (node, users) {
        var users_ck = node.users;
        if (users_ck === undefined) {
            users_ck = [];
        }
        if (users === undefined) {
            users = [];
        }

        for (var i = 0; i < users_ck.length; i++) {
            for (var j = 0; j < users.length; j++) {
                if (users_ck[i].id == users[j] &&
                    users_ck[i].mmdId === undefined) {
                    return {
                        id: users_ck[i].id,
                        name: users_ck[i].name
                    };
                }
            }
        }

        return null;
    },
    //提交人
    submitUser_admin: function (node, users) {
        var users_ck = node.users;
        if (users_ck === undefined) {
            users_ck = [];
        }
        if (users === undefined) {
            users = [];
        }

        for (var i = 0; i < users_ck.length; i++) {
            if (users_ck[i].mmdId === undefined) {
                return {
                    id: users_ck[i].id,
                    name: users_ck[i].name,
                    self: users[0],  //审批人
                    self_name: "name" + users[0]
                };
            }
        }

        return null;
    },
    //测试提交人
    submitUser_test: function (node) {
        const users_ck = node.users;
        if (users_ck === undefined) {
            users_ck = [];
        }

        for (var i = 0; i < users_ck.length; i++) {
            if (users_ck[i].mmdId === undefined) {
                return {
                    id: users_ck[i].id,
                    name: users_ck[i].name,
                    self: users_ck[i].id,  //审批人
                    self_name: users_ck[i].name,
                };
            }
        }

        return null;
    },

    formatWfState: function (state) {
        switch (state) {
            case 0:
                return "待提交";
            case 1:
                return "开始";
            case 2:
                return "退回";
            case 5:
                return "执行中";
            case 8:
                return "取消";
            case 9:
                return "完成";
            default:
                return "未知";
        }
    },
    formatNodeState: function (state) {
        switch (state) {
            case 1:
                return "执行中";
            case 9:
                return "完成";
            default:
                return "未执行";
        }
    },

    //测试初始化数据
    localinit: function (jsonVal) {
        var _time = $_yqFlow.formatDate(new Date());
        jsonVal.info.wfstate = 0;
        jsonVal.info.s_time = _time;
        delete jsonVal.info.e_time;
        delete jsonVal.submit

        var createuser = function () {
            return [{
                "id": "1",
                "name": "张三"
            }]
        };

        var userid = 1;
        var add_user = function () {
            userid++;
            return {
                "id": userid.toString(),
                "name": "姓名" + userid.toString()
            };
        }

        for (var i = 0; i < jsonVal.node.length; i++) {
            delete jsonVal.node[i].todo;

            if (jsonVal.node[i].class == 1 ||
                jsonVal.node[i].class == 2) {
                jsonVal.node[i].users = createuser();
            } else if (jsonVal.node[i].class == 5) {
                jsonVal.node[i].users = [];

                jsonVal.node[i].users.push(add_user());

                if (jsonVal.node[i].duplicateType == 2 ||
                    jsonVal.node[i].duplicateType == 3) {
                    jsonVal.node[i].users.push(add_user());
                    jsonVal.node[i].users.push(add_user());
                } else if (jsonVal.node[i].duplicateType == 4) {
                    jsonVal.node[i].users.push(add_user());
                }
            }

            if (jsonVal.node[i].class == 1) {
                jsonVal.node[i].todo = 1;
                jsonVal.node[i].s_time = _time;
            }
        }

        for (var i = 0; i < jsonVal.link.length; i++) {
            delete jsonVal.link[i].todo;
        }

        return jsonVal;
    },

    //本地流程提交测试
    localtest: function (f_data, submit, callback) {
        var data = JSON.parse(JSON.stringify(f_data));

        var _time = $_yqFlow.formatDate(new Date());

        var s_node = $_yqFlow.node(data, submit.key);

        for (var j = 0; j < s_node.users.length; j++) {
            if (s_node.users[j].id == submit.user.self &&
                s_node.users[j].mmdId === undefined
            ) {
                s_node.users[j].mmdId = submit.mmdId;
                s_node.users[j].e_time = _time;
                if (s_node.users[j].id != submit.user.id) {
                    s_node.users[j].checkin = submit.user.id;
                }

                break;
            }
        }

        if (data.submit === undefined) {
            data.submit = [];
        }
        //审批和执行人相同，删除执行人self，self为流程对应的执行人
        if (submit.user.id == submit.user.self) {
            delete submit.user.self;
        }
        //提交时间
        submit.time = _time;
        //节点第二次开始提交时，记录提交次数
        if (!(data.info.onNum === undefined)) {
            submit.onNum = data.info.onNum;
        }
        data.submit.push(submit);

        //console.log("submit", s_node, submit)

        //执行状态
        var mmdId = -1;

        /*
        duplicateType:通过方式
            1: 单人审批
            2: 最小通过人数
            3: 最小通过百分比
            4: 全部通过
            duplicateNum: 审批阀值
    
        mmdId
            1:提交,同意
            2:重新提交
            0:退回
            8:取消
        */


        //判断审批人数校验
        if (s_node.duplicateType === undefined) {
            s_node.duplicateType = 1;
        }

        if (s_node.duplicateType == 1) {  //单人审批
            mmdId = submit.mmdId;
        } else {
            var mmdId_1 = 0;
            var mmdId_2 = 0;
            var mmdId_0 = 0;
            var mmdId_8 = 0;
            for (var j = 0; j < s_node.users.length; j++) {
                if (!(s_node.users[j].mmdId === undefined)) {
                    if (s_node.users[j].mmdId == 1) {
                        mmdId_1++;
                    } else if (s_node.users[j].mmdId == 2) {
                        mmdId_2++;
                    } else if (s_node.users[j].mmdId == 0) {
                        mmdId_0++;
                    } else if (s_node.users[j].mmdId == 8) {
                        mmdId_8++;
                    }
                }
            }

            if (s_node.duplicateType == 2) {  //最小通过人数
                if (s_node.duplicateNum > s_node.users.length) {
                    s_node.duplicateNum = s_node.users.length;
                }

                if (s_node.duplicateNum <= 1 || s_node.users.length == 1) {
                    mmdId = submit.mmdId;
                } else {
                    if (mmdId_1 >= s_node.duplicateNum) {
                        mmdId = 1;
                    } else if ((mmdId_2 + mmdId_0 + mmdId_8) > 0 && ((mmdId_2 + mmdId_0 + mmdId_8) >
                        (s_node.users.length - s_node.duplicateNum))) {
                        if (mmdId_2 > 0) {
                            mmdId = 2;
                        } else if (mmdId_0 > 0) {
                            mmdId = 0;
                        } else if (mmdId_8 > 0) {
                            mmdId = 8;
                        }
                    }
                }
            } else if (s_node.duplicateType == 3) {  //最小通过百分比
                if (s_node.duplicateNum > 100) {
                    s_node.duplicateNum = 100;
                }

                if (s_node.users.length == 1) {
                    mmdId = submit.mmdId;
                } else {
                    if ((mmdId_1 * 100 / s_node.users.length) >= s_node.duplicateNum) {
                        mmdId = 1;
                    } else if ((mmdId_2 + mmdId_0 + mmdId_8) > 0 &&
                        (((mmdId_2 + mmdId_0 + mmdId_8) * 100 / s_node.users.length) >
                            (100 - s_node.duplicateNum))) {
                        if (mmdId_2 > 0) {
                            mmdId = 2;
                        } else if (mmdId_0 > 0) {
                            mmdId = 0;
                        } else if (mmdId_8 > 0) {
                            mmdId = 8;
                        }
                    }
                }
            } else if (s_node.duplicateType == 4) {  //全部通过
                if (s_node.users.length == 1) {
                    mmdId = submit.mmdId;
                } else {
                    if (mmdId_1 == s_node.users.length) {
                        mmdId = 1;
                    } else if ((mmdId_2 + mmdId_0 + mmdId_8) > 0) {
                        if (mmdId_2 > 0) {
                            mmdId = 2;
                        } else if (mmdId_0 > 0) {
                            mmdId = 0;
                        } else if (mmdId_8 > 0) {
                            mmdId = 8;
                        }
                    }
                }
            }
        }

        if (mmdId == -1) {
            callback({
                error: 0,
                info: "ok",
                wf: data
            });
            return;
        }

        submit.mmdId = mmdId;
        var res = $_yqFlow.submitLines(data, submit);
        if (res.error != 0) {
            callback({
                error: 99,
                info: res.info
            });
            return;
        }

        s_node.todo = 9;
        s_node.e_time = _time;

        data.info.params = res.params;
        var eval_todos = res.todos;

        //退回，记录执行次数+1
        if (mmdId == 2) {
            data.info.onNum = (data.info.onNum === undefined ? 2 : (data.info.onNum + 1));
        }


        var node_keys = [];

        //线完成
        to_link(eval_todos, 0, function (res) {
            if (res.error == 0) {
                res.wf = data;
            }
            callback(res);
        });

        //线处理
        function to_link(links, index, _callback) {
            if (links.length == index) {
                _callback({
                    error: 0,
                    info: "ok"
                });
                return;
            }

            if (data.info.wfstate == 8 || data.info.wfstate == 9) {
                _callback({
                    error: 0,
                    info: "ok"
                });
                return;
            }

            var from = links[index].from;
            var to = links[index].to;
            for (var i = 0; i < data.link.length; i++) {
                if (data.link[i].from == from && data.link[i].to == to) {
                    data.link[i].todo = 9;
                    break;
                }
            }

            //下一节点
            to_node(to, function (res) {
                if (res.error == 0) {
                    to_link(links, index + 1, _callback);
                } else {
                    _callback(res);
                }
            });
        }

        //线处理
        /*
        主信息：              class
            9000 主信息    
        点：
            9001 开始节点  1
            9002 退回节点  2
    
            9005 执行节点  5
            9007 程序节点  7
            9006 判断节点  6
    
            9008 取消节点  8
            9009 结束节点  9
    
            9010 文档节点
        线
            9099 线
        */

        function to_node(key, _callback) {
            var _node = $_yqFlow.node(data, key);
            if (_node === null) {
                _callback({
                    error: 0,
                    info: "ok"
                });
                return;
            }

            _node.s_time = _time;

            if (_node.class == 1 ||  //开始节点
                _node.class == 2 ||  //退回节点
                _node.class == 5     //审批节点
            ) {
                delete _node.endTime;
                _node.todo = 1;

                //流程状态
                data.info.wfstate = _node.class;

                remove_next(key, function (res) {
                    _callback(res);
                });
            } else if (_node.class == 6) {  //判断节点
                _node.todo = 9;

                //流程状态
                data.info.wfstate = 5;

                //执行判断
                var links_6 = $_yqFlow.toLines(data, key);
                var eval_links_6 = $_yqFlow.evalTodos(links_6, data.info.params);

                to_link(eval_links_6, 0, function (res) {
                    _callback(res);
                });
            } else if (_node.class == 7) {   //程序节点
                _node.todo = 9;

                //流程状态
                data.info.wfstate = 5;

                //执行判断 测试流程默认同意
                var links_7 = $_yqFlow.todos(data, key, 1);
                var eval_links_7 = $_yqFlow.evalTodos(links_7, data.info.params);
                to_link(eval_links_7, 0, function (res) {
                    _callback(res);
                });
            } else if (_node.class == 8 ||   //取消节点
                _node.class == 9) {    //结束节点
                _node.todo = 9;

                //流程状态
                data.info.wfstate = _node.class;
                data.info.e_time = _time;
                _callback({
                    error: 0,
                    info: "ok"
                });
            }
        }


        //移除后面线和节点的状态
        function remove_next(key, _callback) {
            var lines = $_yqFlow.toLines(data, key);

            run_lines(0, function (res) {
                _callback(res);
            });

            function run_lines(i, __callback) {
                if (i == lines.length) {
                    __callback({
                        error: 0,
                        info: "ok"
                    });

                    return;
                }

                var node = $_yqFlow.node(data, lines[i].to);
                if (node === null) {
                    __callback({
                        error: 9,
                        info: "节点[key=" + lines[i].to + "]不存在。"
                    });

                    return;
                }

                if (node.class == 5 || node.class == 6 ||
                    node.class == 7) {
                    for (var j = 0; j < node_keys.length; j++) {
                        if (node_keys[j] == node.key) {
                            __callback({
                                error: 9,
                                info: "节点[" + node.text + "]存在递归，请检查流程。"
                            });

                            return;
                        }
                    }

                    node_keys.push(lines[i].to);
                }


                //终点为退回开始、节点，保留线的状态
                if (!(node.class == 1 || node.class == 2)) {
                    delete lines[i].todo;
                    delete node.todo;
                }

                if (node.class == 1 || node.class == 2 || node.class == 5) {
                    delete node.s_time;
                    delete node.e_time;
                    for (var j = 0; j < node.users.length; j++) {
                        if (!(node.users[j].mmdId === undefined)) {
                            delete node.users[j].mmdId;
                            delete node.users[j].e_time;
                            delete node.users[j].checkin;
                        }
                    }
                }

                if (node.class == 5 || node.class == 6 ||
                    node.class == 7) {
                    remove_next(lines[i].to, function (res) {
                        if (res.error == 0) {
                            run_lines(i + 1, __callback);
                        } else {
                            __callback(res);
                        }
                    });
                } else {
                    run_lines(i + 1, __callback);
                }
            }
        }
    },
    //本地更新用户数据
    localUppUser: function (wf_data, key, users, callback) {
        for (var i = 0; i < wf_data.node.length; i++) {
            if (wf_data.node[i].key == key) {
                wf_data.node[i].roleIsEdit = true;
                wf_data.node[i].users = users;
                break;
            }
        }

        callback(wf_data);
    },

    /*
       获取流程定义信息
       ids：流程版本id，多个用","[逗号]分隔，id1,id2
    */
    wfRows: function (ids, callback) {
        const formData = new FormData();
        formData.append("action", "wfs");
        formData.append("ids", ids);

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },
    /*
        获取流程实例信息
    */
    wfData: function (pp, callback) {
        const formData = new FormData();
        formData.append("action", "select");
        formData.append("dbname", pp.dbname);
        formData.append("tbname", pp.tbname);
        formData.append("id", pp.id);

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },
   
     //获取流程base信息
     wfInfo: function (wfid, callback) {
        const formData = new FormData();
        formData.append("action", "wfinfo");
        formData.append("id", wfid);

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },
   
    //获取流程json信息
    wfJson: function (wfid, callback) {
        const formData = new FormData();
        formData.append("action", "wfjson");
        formData.append("id", wfid);

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                if(res.error==0){
                    res.wf.info.stamp = res.stamp;
                }
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },
    //删除流程
    wfDel: function (wfid, callback) {
        const formData = new FormData();
        formData.append("action", "del");
        formData.append("id", wfid);

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },

    //流程初始化
    /*
        init_data:流程初始化参数
        callback:回调
        is_test:测试，默认：否

        init_data= {
            verId:"111111",   //流程版本id
            case_when:"",     //流程过滤条件
            params:{   //初始化数据设置
                name1:"value1",
                name2:"value2"
            },
            parameter:{   //执行人输入参数
                user_id:"value1",
                org_id:"value2",
                other1:"1"
            },
            wfName:"我的流程",
            topic:"测试数据",
            dbName:"yqbase",
            tbName:"a_test_m",
            tbId:"sid1111-1-1" //表记录id
        }
    */
    wfInit: function (init_data, callback, is_test) {
        if (is_test === undefined) {
            is_test = false;
        }

        const formData = new FormData();
        formData.append("action", is_test ? "init_test" : "init");
        formData.append("init", JSON.stringify(init_data));

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                if(res.error==0){
                    res.wf.info.stamp = res.stamp;
                }
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },

    //流程提交
    /*
        data:  测试为 流程数据，执行时为流程实例id
        submit:提交参数数据
        callback:回调
        is_test:测试，默认：否

    
    submit = {
                "initId": "1111-111-111",
                "key": 1,
                "mmdId": 1,
                "params": {
                    "name1": true,
                    "name2": 80
                },
                "time": "2025-01-25 08:56:07",
                "user": {
                    "id": "1",
                    "name": "张三"
                },
                "stamp": "2025-01-25 08:50:01",
            }
    */
    wfSubmit: function (data, submit, callback, is_test) {
        if (is_test === undefined) {
            is_test = false;
        }

        const formData = new FormData();
        formData.append("action", is_test ? "submit_test" : "submit");
        if (is_test) {
            formData.append("wf", JSON.stringify(data));
        } else {
            formData.append("wf", data);
        }
        formData.append("submit", JSON.stringify(submit));

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                if(res.error==0){
                    res.wf.info.stamp = res.stamp;
                }
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },

    //本地更新用户数据
    wfUppUser: function (data, key, users, is_test, callback) {
        const formData = new FormData();
        formData.append("action", (is_test ? "submit_uppuser" : "uppuser"));
        if (is_test) {
            formData.append("wf", JSON.stringify(data));
        } else {
            formData.append("wf", data);
        }
        formData.append("params", JSON.stringify({
            key: key,
            users: users
        }));

        $.ajax({
            type: 'POST',
            url: "/_wf.html",
            data: formData,
            processData: false,
            contentType: false,
            dataType: "json",
            success: function (res) {
                if(res.error==0){
                    res.wf.info.stamp = res.stamp;
                }
                callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.log(XMLHttpRequest.responseText);
                callback({ "error": 99, "info": errorThrown });
            }
        });
    },
}